﻿#include "AACDecoder.h"
#include <winsock.h>
#include <stdio.h>

#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"libfaad.lib")

AACDecoder::AACDecoder() :
	_handle(nullptr),
	_samplerate(-1),
	_channel(-1),
	_init(false) 
{

}

AACDecoder::~AACDecoder() 
{
	close();
}

int AACDecoder::open(unsigned char defObjectType, unsigned long defSampleRate)
{
	NeAACDecConfigurationPtr conf = nullptr;
	unsigned long cap = NeAACDecGetCapabilities();

	_handle = NeAACDecOpen();

	if (!_handle) 
	{
		close();
		return -1;
	}

	conf = NeAACDecGetCurrentConfiguration(_handle);

	if (!conf) 
	{
		close();
		return -1;
	}

	conf->defObjectType = defObjectType;
	conf->defSampleRate = defSampleRate;
	conf->outputFormat = FAAD_FMT_16BIT;
	conf->dontUpSampleImplicitSBR = 1;

	NeAACDecSetConfiguration(_handle, conf);

	return 0;
}

void AACDecoder::close()
{
	if (_handle) 
	{
		NeAACDecClose(_handle);
		_handle = nullptr;
	}

	_init = false;
}

/** 解码 */
int AACDecoder::decode(char* aacBuf, unsigned long int aacBufLen, char* outBuf)
{
	if (_handle && !_init)
	{
		long res = NeAACDecInit(_handle, (unsigned char*)aacBuf, aacBufLen,
			&_samplerate, &_channel);
		if (res < 0)
		{
			printf("neAACDec cannot init.");
			return -2;
		}
		_init = true;
	}

	unsigned int donelen = 0;
	while (donelen < aacBufLen)
	{
		unsigned int framelen = getFrameLenth(aacBuf + donelen);

		if (donelen + framelen > aacBufLen)
		{
			break;
		}

		// decode
		NeAACDecFrameInfo info;
		void* buf = NeAACDecDecode(_handle, &info,
			(unsigned char*)aacBuf + donelen, framelen);

		if (buf && info.error == 0)
		{
			FILE* fp = fopen("abc.pcm", "a+");
			unsigned short monoBuffer[4096];

			for (int i = 0, j = 0; i < info.samples; i += 2, j++)
			{
				monoBuffer[j] = (*((unsigned short*)buf + i + *(unsigned short*)buf + i + 1)) / 2;
			}
			fwrite(monoBuffer, 1, info.samples, fp);
			fclose(fp);
		}
		else
		{
			printf("NeAACDecDecode() failed info.error %d\n", info.error);
		}

		donelen += framelen;
	}

	return 0;
}

unsigned int AACDecoder::getFrameLenth(const char* aacHeader) const
{
	unsigned int len = *(unsigned int*)(aacHeader + 3);
	len = ntohl(len); // Little Endian
	len = len << 6;
	len = len >> 19;
	return len;
}